using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Jbe.TestSuite.TestDevice.Manager;
using Jbe.TestSuite.Infrastructure.Interface;
using Jbe.TestSuite.TestDevice.Manager.Interface.Services;
using Jbe.TestSuite.TestDevice.Manager.Services;
using Jbe.TestSuite.TestDevice.Manager.Tests.Mocks;
using Jbe.TestSuite.TestDevice.Manager.Constants;
using Microsoft.Practices.CompositeUI.EventBroker;

namespace Jbe.TestSuite.TestDevice.Manager.Tests
{
    /// <summary>
    /// Summary description for TestDeviceManagerFixture
    /// </summary>
    [TestClass]
    public class TestDeviceManagerFixture : FixtureBase
    {
        public event EventHandler<EventArgs<IList<IControlView>>> SelectedDeviceControllersChanged;

        private ControlledWorkItem<ModuleController> workItem;
        private TestDeviceManager manager;
        private MockDeviceControllerFactory mockFactory;
        private MockDevice mockDevice;
        private IList<IControlView> deviceControllers;

        [TestInitialize]
        public override void TestInitialize()
        {
            base.TestInitialize();

            workItem = rootWorkItem.WorkItems.AddNew<ControlledWorkItem<ModuleController>>();
            manager = workItem.Services.AddNew<TestDeviceManager, ITestDeviceManager>();

            workItem.EventTopics[EventTopicNames.SelectedControlViewsChanged].AddPublication(this,
                "SelectedDeviceControllersChanged", workItem, PublicationScope.Global);
            workItem.EventTopics[EventTopicNames.ControlViewsChanged].AddSubscription(this,
                "DeviceControllersChangedHandler", workItem, ThreadOption.Publisher);

            mockFactory = new MockDeviceControllerFactory();
            mockDevice = new MockDevice();
        }

        [TestMethod]
        public void RegisterFactory()
        {
            bool assertion;
            
            // Register a factory
            manager.Register(mockFactory);

            // Register null
            assertion = false;
            try { manager.Register((IControlViewFactory)null); }
            catch (ArgumentNullException) { assertion = true; }
            Assert.IsTrue(assertion, "The expected exception was not thrown.");

            // Register an invalid factory
            assertion = false;
            MockDeviceControllerFactory invalidFactory = new MockDeviceControllerFactory();
            invalidFactory.ProfileName = null;
            try { manager.Register(invalidFactory); }
            catch (ArgumentNullException) { assertion = true; }
            Assert.IsTrue(assertion, "The expected exception was not thrown.");
        }

        [TestMethod]
        public void RegisterDevice()
        {
            bool assertion;

            // Register null
            assertion = false;
            try { manager.Register((IDevice)null); }
            catch (ArgumentNullException) { assertion = true; }
            Assert.IsTrue(assertion, "The expected exception was not thrown.");
            
            // Register a device without any controllers registered
            assertion = false;
            try { manager.Register(mockDevice); }
            catch (ArgumentException) { assertion = true; }
            Assert.IsTrue(assertion, "The expected exception was not thrown.");

            // Register a device without a controller for the same profile registered
            assertion = false;
            manager.Register(mockFactory);
            mockDevice.ProfileName = "WrongProfile";
            try { manager.Register(mockDevice); }
            catch (ArgumentException) { assertion = true; }
            Assert.IsTrue(assertion, "The expected exception was not thrown.");

            // Register a device
            mockDevice.ProfileName = MockDeviceController.ProfileName;
            manager.Register(mockDevice);
            Assert.AreEqual(1, deviceControllers.Count, "deviceControllers.Count");
            Assert.AreEqual(1, manager.ControlViews.Count, "manager.DeviceControllers.Count");
        }

        [TestMethod]
        public void Deregister()
        {
            manager.Register(mockFactory);
            manager.Register(mockDevice);

            // Deregister the device
            Assert.IsTrue(manager.Deregister(mockDevice), "manager.Deregister(...)");
            Assert.AreEqual(0, deviceControllers.Count, "deviceControllers.Count");
            Assert.AreEqual(0, manager.ControlViews.Count, "manager.DeviceControllers.Count");

            // Deregister the same device a second time
            Assert.IsFalse(manager.Deregister(mockDevice), "manager.Deregister(...)");
            Assert.AreEqual(0, deviceControllers.Count, "deviceControllers.Count");
            Assert.AreEqual(0, manager.ControlViews.Count, "manager.DeviceControllers.Count");
        }

        [TestMethod]
        public void EventAndCommands()
        {
            manager.Register(mockFactory);
            manager.Register(mockDevice);
            
            MockDeviceController controller = (MockDeviceController)manager.ControlViews[0];
            
            // Select the device controller by firing the event
            OnSelectedDeviceControllersChanged(manager.ControlViews);
            Assert.AreEqual(manager.ControlViews.Count, manager.SelectedControlViews.Count);
            
            // Execute the ShowDevice command
            workItem.Commands[CommandNames.ShowDevice].Execute();
            Assert.IsTrue(controller.Shown, "controller.Shown");

            // Execute the CloseDevice command
            workItem.Commands[CommandNames.CloseDevice].Execute();
            Assert.IsTrue(controller.Closed, "controller.Closed");
        }

        public void DeviceControllersChangedHandler(object sender, EventArgs<IList<IControlView>> e)
        {
            deviceControllers = e.Data;
        }

        protected virtual void OnSelectedDeviceControllersChanged(IList<IControlView> controllers)
        {
            if (SelectedDeviceControllersChanged != null) 
            { 
                SelectedDeviceControllersChanged(this, new EventArgs<IList<IControlView>>(controllers)); 
            }
        }
    }
}
